﻿#!/usr/bin/env python
from head import *

class JzBms:
    #head field
    player          = None
    genre           = None
    title           = None
    artist          = None
    playlevel       = None
    bpm             = None
    rank            = None
    wav             = None
    id              = None
    roundgap        = '16'

BEAT_COUNT_OF_ROUND = 8
KEY_COUNT_OF_BEAT = 8
REAL_KEY_COUNT_OF_BEAT = 240


KEY = [11,12,13,14,15]      #按键列表
ele = JzBms()               #当前操作的bms对应的实例 
gRoundinfo = []             #当前操作的bms对应的轮列表
gBreakPoint={}              #空轮信息

def LoadJZBMS(name):
    global ele
    Line = []
    f = open(name)
    for item in f:
        item = item.strip()
        if item:
            Line.append(item)
    f.close()
    datafield = []
    for i in xrange(len(Line)):
        p = Line[i].split(' ')

        if len(p) == 2:
            #head field
            if p[0] == '#PLAYER':
                ele.player = p[1]
                continue
        
            elif p[0] == '#GENRE':
                ele.genre = p[1]
                continue
        
            elif p[0] == '#TITLE':
                ele.title = p[1].decode('gbk').encode('utf-8')
                continue

            elif p[0] == '#ARTIST':
                ele.artist = p[1]
                continue

            elif p[0] == '#BPM':
                ele.bpm = p[1]
                continue

            elif p[0] == '#PLAYLEVEL':
                ele.playlevel = p[1]
                continue

            elif p[0] == '#RANK':
                ele.rank = p[1]
                continue

            elif p[0] == '#WAV02':
                ele.wav = p[1]
                continue
            
        if len(p) == 1 and len(Line[i].split(':')) ==2:
            #data field
            if int(Line[i].split(':')[0][1:])/100 == 0:
                pass
            else:
                datafield.append(Line[i])
    Parse(datafield)

def Parse(data):
    sectionlist = []
    length = len(data)
    sectiondata = []
    LastSection = 0
    for i in xrange(length):
        #logging.info('L:%s'%data[i])
        head = data[i].split(':')[0][1:]
        body = data[i].split(':')[1]
        #key        = int(head)%100
        curSection = int(head)/100
        
        if i==0:
            LastSection = int(data[0].split(':')[0][1:])/100
        elif i==length-1:
            #最后一行，强制写一次数据
            LastSection = -1
        else:
            LastSection = int(data[i-1].split(':')[0][1:])/100

        if curSection != LastSection and curSection != (LastSection+1):
            if i==length-1:
                sectiondata.append((head,body))
                sectionlist.append(sectiondata)
            else:
                sectionlist.append(sectiondata)
                sectiondata = []
                sectiondata.append((head,body))
        else:
            sectiondata.append((head,body))

    Analysis(sectionlist)


class Round:
    ft = '1'
    rule = ''

def Analysis(sectionlist):
    #i = 0
    for item in sectionlist:
        if len(item) ==1 and int(item[0][0])%100=='16' and item[0][1][0]=='A':
            gBreakPoint[len(gRoundinfo)] = int(item[0][1][1])
            continue
        tmp = []
        #检查当前轮是否有特殊标记
        this = Round()
        for e in item:
            if int(e[0])%100 == 16 and e[1][0:2] == '07':
                this.ft = '2'
                continue
            if int(e[0])%100 == 16 and e[1][0] == 'A':
                gBreakPoint[len(gRoundinfo)] = int(e[1][1])
                continue
            tmp.append(e)
        
        if len(tmp) == 8:
            #分批做,两轮,走到这里来是两轮
            p11,p12,p13,p14=SplitData(tmp[0:4])
            p21,p22,p23,p24=SplitData(tmp[4:])
            r11 = ParseJZ(p11)
            r12 = ParseJZ(p12)
            r13 = ParseJZ(p13)
            r14 = ParseJZ(p14)

            r21 = ParseJZ(p21)
            r22 = ParseJZ(p22)
            r23 = ParseJZ(p23)
            r24 = ParseJZ(p24)
            this.rule = '0x'+str(r11)+str(r12)+str(r13)+str(r14)+str(r21)+str(r22)+str(r23)+str(r24)
        else:
            #单轮
            p1,p2,p3,p4 = SplitData(tmp)
            r1 = ParseJZ(p1)
            r2 = ParseJZ(p2)
            r3 = ParseJZ(p3)
            r4 = ParseJZ(p4)
            this.rule = '0x'+str(r1)+str(r2)+str(r3)+str(r4)
        gRoundinfo.append(this)


def SplitData(mydata):
    #每一轮的每一拍
    p1 = []
    p2 = []
    p3 = []
    p4 = []
    for i in xrange(len(mydata)):
        head,data = mydata[i]
        #print 'head:%s,data:%s'%(head,data)
        key = head[-2:]
        data = Align(data, 32)
        #print data
        pp1= (key+':'+data[0:8])
        pp2= (key+':'+data[8:16])
        pp3= (key+':'+data[16:24])
        pp4= (key+':'+data[24:])
        p1.append(pp1)
        p2.append(pp2)
        p3.append(pp3)
        p4.append(pp4)
    result = (p1,p2,p3,p4)
    return result

def ParseJZ(data):
    if len(data) <= 5:
        dic = {}
        #先检查有没有空格键，且空格键是否不为0，如果不为0，直接返回0，否则继续下面规则
        for item in data:
            key = item.split(':')[0]
            pos = item.split(':')[1]
            dic[key] = pos
            if key == '15' and int(pos) != 0:
                #走这说明有空格键，此位置直接是空格
                return RULE_SPACE
        
        patter = 0
        for key in dic.keys():
            patter |= int(dic[key],16)
        patters = hex(patter)
        if patters == '0x1010100':
            #三个位置都有键
            for k in dic.keys():
                if hex(int(dic[k],16)) == '0x1010100':
                    #说明有三个键相同
                    return RULE_AAA
                if hex(int(dic[k],16)) == '0x1000100':
                    #1,3位置键相同
                    return RULE_ABA
                if hex(int(dic[k],16)) == '0x10100' or hex(int(dic[k],16)) == '0x1010000':
                    #2,3号位置键相同,或者1,2号位置键相同
                    return RULE_AAB
            #走到这还没出去，我操，说明三个键都不一样
            return RULE_ABC
        
        if patters == '0x1010000' or patters == '0x10100' or patters == '0x1000100':
            #1，2位置，或者2,3位置有键,或者1,3位置有键盘，且这一拍只有两个键
            for k in dic.keys():
                if hex(int(dic[k],16)) == '0x1010000' or hex(int(dic[k],16)) == '0x1000100' or hex(int(dic[k],16)) == '0x10100':
                    #分别是1,2;1,3;2,3位置有两个相同的键
                    return RULE_AA
            #走到这说明两个键肯定不一样
            return RULE_AB
            
        if patters == '0x1000000' or patters=='0x100' or patters == '0x10000':
            #分别是1，2，3位置有一个键
            return RULE_A

        #一般不可能走到这来，如果走到了就给个空格吧
        return RULE_SPACE

def SaveJzXML(name):
    global gRoundinfo, gBreakPoint
    if name.split('.')[1].lower() != 'bms':
        return False
    
    LoadJZBMS(name)
    doc = Document()
    root_element = doc.createElement('musics')
    doc.appendChild(root_element)

    music = doc.createElement('music')
    music.setAttribute('id',name.split('.')[0])
    music.setAttribute('level',ele.playlevel)
    music.setAttribute('roundgap','16')

    root_element.appendChild(music)
    i = 0
    num = 0
    for item in gRoundinfo:
        num = gBreakPoint.get(i+1)
        if num!=None and num!=0:
            #说明在这一节有空轮，先加空轮
            for j in xrange(num):
                emptyround = doc.createElement('round')
                emptyround.setAttribute('type','3')
                music.appendChild(emptyround)
                
        round = doc.createElement('round')
        round.setAttribute('type',item.ft)
        round.setAttribute('rule',item.rule)
        music.appendChild(round)
        i += 1
    s = doc.toprettyxml(indent='    ',encoding='UTF-8')
    if name[0] == '1':
        folder = 'LB1'
    elif name[0] == '2':
        folder = 'LB2'
    else:
        return
    
    if not MACRO_DEBUG:
        f = open('..'+os.sep+folder+os.sep+name.split('.')[0]+'.xml','w')
    else:
        f = open(name.split('.')[0]+'.xml','w')
    f.write(s)
    f.close()

    return True
    
if __name__ == '__main__':
    SaveJzXML('10001.bms')
    
    
